//
// Created by Tony on 2024/5/29.
//

#ifndef RT_CODE_CLASS_H
#define RT_CODE_CLASS_H

#include "../../compiler/SymbolTable.h"
#include "../Slot.h"
#include "AccessFlag.h"
#include "Field.h"
#include "Method.h"
#include "constant_pool/ConstantPool.h"
#include <cstdint>

namespace RtData {
class Object;
}

namespace RtCode {

class ClassTable;

class Class : public enable_shared_from_this<Class> {
    string mName;
    AccessFlag mAccessFlags;
    shared_ptr<ConstantPool> mConstantPool;
    vector<shared_ptr<Field>> mFields;
    vector<shared_ptr<Method>> mMethods;
    vector<Runtime::Slot> mStaticVars;
    uint16_t mInstanceSlotCount{0};
    uint16_t mStaticSlotCount{0};

    weak_ptr<ClassTable> mClassTable;

    // status
    bool mIsInitStarted{false};

public:
    Class(string name, const shared_ptr<ClassTable>& classTable);

    const string& getName() const { return mName; }
    shared_ptr<ClassTable> getClassTable() const { return mClassTable.lock(); }
    ConstantPool& getConstantPool();

    void setAccessFlag(AccessFlag flags) { mAccessFlags = flags; }
    const AccessFlag& getAccessFlag() const { return mAccessFlags; }

    void addField(const shared_ptr<Field>& field);
    shared_ptr<Field> getField(const string& name);
    vector<Runtime::Slot>& getStaticVars() { return mStaticVars; }

    void addMethod(const shared_ptr<Method>& method);
    shared_ptr<Method> getMethod(const string& name);

    shared_ptr<Method> getClassInitMethod();
    shared_ptr<Method> getMainMethod();
    shared_ptr<Method> getObjectInitMethod();

    bool isInitStarted() const { return mIsInitStarted; }
    void startInit() { mIsInitStarted = true; }

    RtData::Object* newObject();

    shared_ptr<Compiler::SymbolTable> getSymbolTable();

    string toString();
};

} // namespace RtCode

#endif // RT_CODE_CLASS_H
